import React, {Component} from 'react';
import PropTypes, { array } from 'prop-types';

import 'react-tabulator/lib/styles.css'; // required styles
//import 'react-tabulator/lib/css/tabulator.min.css'; // theme
import { ReactTabulator } from 'react-tabulator'
import {resolveProps, resolveProp} from 'dash-extensions'

/**
 * DashTabulator is an implementation of the React Tabulator from 
 * https://github.com/ngduc/react-tabulator/ and https://github.com/olifolkerd/tabulator.
 * It takes a property, `column`, and `data`
 * displays it in tabulator.
 * The `options` property is passed to Tabulator to perform regular options
 * downloading as xlsx is enabled by default.
 */
export default class DashTabulator extends Component {
    constructor(props) {

        super(props);
        this.ref = null;
        
        this.theme = props.theme;
        switch(this.theme) {
            
            case null : // theme not set use default
            case 'tabulator': // name of default theme
            case 'default' : // default - expect the unexpected 
                require('react-tabulator/lib/css/tabulator.min.css');
                break
            case 'tabulator_modern' : 
                require('react-tabulator/lib/css/tabulator_modern.min.css');
                break;
            case 'tabulator_midnight':
                require('react-tabulator/lib/css/tabulator_midnight.min.css');
                break;
            case 'tabulator_simple' :
                require('react-tabulator/lib/css/tabulator_simple.min.css');
                break;
            case 'tabulator_site' :
                require('react-tabulator/lib/css/tabulator_site.min.css');
                break;
            case 'bootstrap/tabulator_bootstrap' :
                require('react-tabulator/lib/css/bootstrap/tabulator_bootstrap.min.css');
                break;
            case 'bootstrap/tabulator_bootstrap4' :
                require('react-tabulator/lib/css/bootstrap/tabulator_bootstrap4.min.css');
                break;   
            case 'bulma/tabulator_bulma' :
                require('react-tabulator/lib/css/bulma/tabulator_bulma.min.css');
                break;
            case 'materialize/tabulator_materialize' :
                require('react-tabulator/lib/css/materialize/tabulator_materialize.min.css'); 
                break;
            case 'semantic-ui/tabulator_semantic-ui':
                require('react-tabulator/lib/css/semantic-ui/tabulator_semantic-ui.min.css'); 
                break; 
        }
    }
    
    /*
     * setProps calls render() which can break DOM updates like changing a cell to an editor 
     *          or resetting a filter field as it's being typed, shouldRerender can be used to turn off render
     *          as setProps is being called
     */
    shouldRerender = false; 
    
    rowClick = (e, row) => {
        //console.log('ref table: ', this.ref.table); // this is the Tabulator table instance
        //console.log('rowClick id: ${row.getData().id}', row, e);
        //console.log( this.ref.table.getSelectedData());
        this.shouldRerender = false; 
        this.props.setProps({rowClicked: row._row.data})
        this.shouldRerender = true;
    };

    rowSelected = (data, row) => {
        this.shouldRerender = false;
        this.props.setProps({multiRowsClicked: data }) 
        this.shouldRerender = true;
    }

    downloadData = () => {
        let type = this.props.downloadButtonType.type || "csv";
        let filename = this.props.downloadButtonType.filename || "data";
        filename += `.${type}`
        this.ref.table.download(type, filename);
    };

    clearFilters = () => {
        this.ref.table.clearFilter(true);
    }

    shouldComponentUpdate() {
        return this.shouldRerender;
    }

    render() {
        const {id, data, setProps, columns, options, rowClicked, multiRowsClicked, cellEdited, dataChanged,
            downloadButtonType, clearFilterButtonType, initialHeaderFilter, dataFiltering, dataFiltered} = this.props;
        
        // Interpret column formatters as function handles.
        // TODO: resolve any columns method
        for(let i=0; i < columns.length; i++){
            let header = columns[i];
            
            for (let key in header){ 
                let o = header[key];
                console.log(key);
                console.log(o);
                if (o instanceof Object) { 
                    header[key] = resolveProp(o, this);
                }
            }
        }

        // check all options for a global windows function in the assets folder
        for (let key in options) {
            let o = options[key] 
            if (o instanceof Object) {
                options[key] = resolveProp(o, this)    
            }
        } 
        const options2 = {...options, 
            downloadDataFormatter: (data) => data,
            downloadReady: (fileContents, blob) => blob
        }

        let downloadButton;
        if (downloadButtonType) {
            downloadButton = <button type="button" onClick={this.downloadData} className={downloadButtonType.css} id="download">{downloadButtonType.text}</button>
        }
        let clearFilterButton;
        if (clearFilterButtonType) {
            clearFilterButton = <button type="button" onClick={this.clearFilters} className={clearFilterButtonType.css} id="clearFilters">{clearFilterButtonType.text}</button>
        }

        return (
            <div>
                {downloadButton}{clearFilterButton}
            <ReactTabulator
                ref={ref => (this.ref = ref)}
                data={data}
                columns={columns}
                tooltips={true}
                layout={"fitData"}
                options={options2}
                rowClick={this.rowClick}
                cellEdited={(cell) => {
                    //console.log(cell)
                    var edited =new Object() 
                    edited.column = cell.getField()
                    edited.initialValue = cell.getInitialValue()
                    edited.oldValue = cell.getOldValue()
                    edited.value = cell.getValue()
                    edited.row = cell.getData()
                    this.props.setProps({cellEdited: edited})
                }}
                rowSelectionChanged={this.rowSelected}
                dataChanged={(newData) => {
                    this.props.setProps({dataChanged: newData})
                }}
                dataFiltering={(filters) => {
                    //this.props.setProps({dataFiltering: this.getHeaderFilters()})
                    var filterHeaders = new Array()
                    if (this.ref) {
                        filterHeaders =this.ref.table.getHeaderFilters() 
                    }
                    this.shouldRerender = false;
                    this.props.setProps({dataFiltering:filterHeaders})
                    this.shouldRerender = true;
                }}
                dataFiltered={(filters, rows) => {
                    let rowData = new Array(rows.length)
                    rows.forEach(r => rowData.push(r.getData()))
                    var filterHeaders = new Array()
                    if (this.ref) {
                        filterHeaders =this.ref.table.getHeaderFilters() 
                        //console.log(this.ref.table.getHeaderFilters())
                        
                    }
                    
                    this.shouldRerender = false;
                    this.props.setProps(
                                        {
                                            dataFiltered: {
                                                            filters: filterHeaders,
                                                            rows: rowData
                                                        }
                                        }
                                        )
                    this.shouldRerender = true;
                    }
                } // dataFiltered end

                initialHeaderFilter={initialHeaderFilter}

            />
            </div>
        );
    }
}

DashTabulator.defaultProps = {
    columns : [],
    data: [],
    theme: null
};

DashTabulator.propTypes = {
    /**
     * The ID used to identify this component in Dash callbacks.
     */
    id: PropTypes.string,

    /**
     * theme
     */
    theme : PropTypes.string,

    /**
     * A label that will be printed when this component is rendered.
     */
    columns: PropTypes.array,

    /**
     * The value displayed in the input.
     */
    data: PropTypes.array,

    /**
     * Dash-assigned callback that should be called to report property changes
     * to Dash, to make them available for callbacks.
     */
    setProps: PropTypes.func,

    /**
     * Tabulator Options
     */

    options: PropTypes.object,

    
    /**
     * rowClick captures the row that was clicked on
     */
    rowClicked: PropTypes.object,

    /**
     * multiRowsClicked, when multiple rows are clicked
     */
    multiRowsClicked: PropTypes.array,

    /**
     * cellEdited captures the cell that was clicked on
     */
    cellEdited: PropTypes.object,

    /**
     * dataChanged captures the cell that was clicked on
     */
    dataChanged: PropTypes.array,
    
    
    /**
     * downloadButtonType, takes a css style, text to display on button, type is file type to download
     * e.g.
     *  downloadButtonType = {"css": "btn btn-primary", "text":"Export", "type":"xlsx"}
     */
    downloadButtonType: PropTypes.object,

    /**
     * clearFilterButtonType, takes a css style, text to display on button
     * e.g.
     *  clearFilterButtonType = {"css": "btn btn-primary", "text":"Export"}
     */
    clearFilterButtonType: PropTypes.object,

    /**
     * initialHeaderFilter based on http://tabulator.info/docs/4.8/filter#header
     * can take array of filters 
     */
    initialHeaderFilter: PropTypes.array, 

    /**
     * dataFiltering based on http://tabulator.info/docs/4.8/callbacks#filter
     * The dataFiltering callback is triggered whenever a filter event occurs, before the filter happens.
     */
    dataFiltering: PropTypes.array ,

    /**
     * dataFiltered based on http://tabulator.info/docs/4.8/callbacks#filter
     * The dataFiltered callback is triggered after the table dataset is filtered
     */
    dataFiltered: PropTypes.object,


    /**
     * standard props not used by dash-tabulator directly
     * can be used as part of custom javascript implementations
     */
    rowClick : PropTypes.any,
    tableBuilding : PropTypes.any,
    tableBuilt : PropTypes.any,
    rowDblClick : PropTypes.any,
    rowContext : PropTypes.any,
    rowTap : PropTypes.any,
    rowDblTap : PropTypes.any,
    rowTapHold : PropTypes.any,
    rowAdded : PropTypes.any,
    rowDeleted : PropTypes.any,
    rowMoved : PropTypes.any,
    rowUpdated : PropTypes.any,
    rowSelectionChanged : PropTypes.any,
    rowSelected : PropTypes.any,
    rowDeselected : PropTypes.any,
    rowResized : PropTypes.any,
    cellClick : PropTypes.any,
    cellDblClick : PropTypes.any,
    cellContext : PropTypes.any,
    cellTap : PropTypes.any,
    cellDblTap : PropTypes.any,
    cellTapHold : PropTypes.any,
    cellEditing : PropTypes.any,
    cellEditCancelled : PropTypes.any,
    columnMoved : PropTypes.any,
    columnResized : PropTypes.any,
    columnTitleChanged : PropTypes.any,
    columnVisibilityChanged : PropTypes.any,
    headerClick : PropTypes.any,
    headerDblClick : PropTypes.any,
    headerContext : PropTypes.any,
    headerTap : PropTypes.any,
    headerDblTap : PropTypes.any,
    headerTapHold : PropTypes.any,
    htmlImporting : PropTypes.any,
    htmlImported : PropTypes.any,
    dataLoading : PropTypes.any,
    dataLoaded : PropTypes.any,
    ajaxRequesting : PropTypes.any,
    ajaxResponse : PropTypes.any,
    ajaxError : PropTypes.any,
    dataSorting : PropTypes.any,
    dataSorted : PropTypes.any,
    renderStarted : PropTypes.any,
    renderComplete : PropTypes.any,
    pageLoaded : PropTypes.any,
    localized : PropTypes.any,
    dataGrouping : PropTypes.any,
    dataGrouped : PropTypes.any,
    groupVisibilityChanged : PropTypes.any,
    groupClick : PropTypes.any,
    groupDblClick : PropTypes.any,
    groupContext : PropTypes.any,
    groupTap : PropTypes.any,
    groupDblTap : PropTypes.any,
    groupTapHold : PropTypes.any,
    movableRowsSendingStart : PropTypes.any,
    movableRowsSent : PropTypes.any,
    movableRowsSentFailed : PropTypes.any,
    movableRowsSendingStop : PropTypes.any,
    movableRowsReceivingStart : PropTypes.any,
    movableRowsReceived : PropTypes.any,
    movableRowsReceivedFailed : PropTypes.any,
    movableRowsReceivingStop : PropTypes.any,
    validationFailed : PropTypes.any,
    clipboardCopied : PropTypes.any,
    clipboardPasted : PropTypes.any,
    clipboardPasteError : PropTypes.any,
    downloadReady : PropTypes.any,
    downloadComplete : PropTypes.any,
    selectableCheck : PropTypes.any

};
